summaryrefslogtreecommitdiffstats
path: root/Source/cmListFileCache.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmListFileCache.cxx')
-rw-r--r--Source/cmListFileCache.cxx171
1 files changed, 135 insertions, 36 deletions
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index f198ac3..1cc66f4 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -398,73 +398,172 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
}
}
-cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot snapshot,
- cmCommandContext const& cc)
- : Snapshot(snapshot)
+struct cmListFileBacktrace::Entry: public cmListFileContext
{
- if (!this->Snapshot.IsValid())
+ Entry(cmListFileContext const& lfc, Entry* up):
+ cmListFileContext(lfc), Up(up), RefCount(0)
{
- return;
+ if (this->Up)
+ {
+ this->Up->Ref();
+ }
}
-
- // Record the entire call stack now so that the `Snapshot` we
- // save for later refers to a long-lived scope. This avoids
- // having to keep short-lived scopes around just to extract
- // their backtrace information later.
-
- cmListFileContext lfc =
- cmListFileContext::FromCommandContext(
- cc, this->Snapshot.GetExecutionListFile());
- this->push_back(lfc);
-
- cmState::Snapshot parent = this->Snapshot.GetCallStackParent();
- while (parent.IsValid())
+ ~Entry()
+ {
+ if (this->Up)
+ {
+ this->Up->Unref();
+ }
+ }
+ void Ref()
+ {
+ ++this->RefCount;
+ }
+ void Unref()
{
- lfc.Name = this->Snapshot.GetEntryPointCommand();
- lfc.Line = this->Snapshot.GetEntryPointLine();
- lfc.FilePath = parent.GetExecutionListFile();
- if (lfc.FilePath.empty())
+ if (--this->RefCount == 0)
{
- break;
+ delete this;
}
- this->push_back(lfc);
+ }
+ Entry* Up;
+ unsigned int RefCount;
+};
- this->Snapshot = parent;
- parent = parent.GetCallStackParent();
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom,
+ Entry* up,
+ cmListFileContext const& lfc):
+ Bottom(bottom), Cur(new Entry(lfc, up))
+{
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot bottom, Entry* cur):
+ Bottom(bottom), Cur(cur)
+{
+ if (this->Cur)
+ {
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
}
+}
+
+cmListFileBacktrace::cmListFileBacktrace(): Bottom(), Cur(0)
+{
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmState::Snapshot snapshot):
+ Bottom(snapshot.GetCallStackBottom()), Cur(0)
+{
+}
+
+cmListFileBacktrace::cmListFileBacktrace(cmListFileBacktrace const& r):
+ Bottom(r.Bottom), Cur(r.Cur)
+{
+ if (this->Cur)
+ {
+ assert(this->Bottom.IsValid());
+ this->Cur->Ref();
+ }
+}
- this->Snapshot = this->Snapshot.GetCallStackBottom();
+cmListFileBacktrace&
+cmListFileBacktrace::operator=(cmListFileBacktrace const& r)
+{
+ cmListFileBacktrace tmp(r);
+ std::swap(this->Cur, tmp.Cur);
+ std::swap(this->Bottom, tmp.Bottom);
+ return *this;
}
cmListFileBacktrace::~cmListFileBacktrace()
{
+ if (this->Cur)
+ {
+ this->Cur->Unref();
+ }
+}
+
+cmListFileBacktrace
+cmListFileBacktrace::Push(std::string const& file) const
+{
+ // We are entering a file-level scope but have not yet reached
+ // any specific line or command invocation within it. This context
+ // is useful to print when it is at the top but otherwise can be
+ // skipped during call stack printing.
+ cmListFileContext lfc;
+ lfc.FilePath = file;
+ return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+}
+
+cmListFileBacktrace
+cmListFileBacktrace::Push(cmListFileContext const& lfc) const
+{
+ return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+}
+
+cmListFileBacktrace cmListFileBacktrace::Pop() const
+{
+ assert(this->Cur);
+ return cmListFileBacktrace(this->Bottom, this->Cur->Up);
+}
+
+cmListFileContext const& cmListFileBacktrace::Top() const
+{
+ if (this->Cur)
+ {
+ return *this->Cur;
+ }
+ else
+ {
+ static cmListFileContext const empty;
+ return empty;
+ }
}
void cmListFileBacktrace::PrintTitle(std::ostream& out) const
{
- if (this->empty())
+ if (!this->Cur)
{
return;
}
- cmOutputConverter converter(this->Snapshot);
- cmListFileContext lfc = this->front();
- lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ cmOutputConverter converter(this->Bottom);
+ cmListFileContext lfc = *this->Cur;
+ if (!this->Bottom.GetState()->GetIsInTryCompile())
+ {
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ }
out << (lfc.Line ? " at " : " in ") << lfc;
}
void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
{
- if (this->size() <= 1)
+ if (!this->Cur || !this->Cur->Up)
{
return;
}
- out << "Call Stack (most recent call first):\n";
- cmOutputConverter converter(this->Snapshot);
- for (const_iterator i = this->begin() + 1; i != this->end(); ++i)
+ bool first = true;
+ cmOutputConverter converter(this->Bottom);
+ for (Entry* i = this->Cur->Up; i; i = i->Up)
{
+ if (i->Name.empty())
+ {
+ // Skip this whole-file scope. When we get here we already will
+ // have printed a more-specific context within the file.
+ continue;
+ }
+ if (first)
+ {
+ first = false;
+ out << "Call Stack (most recent call first):\n";
+ }
cmListFileContext lfc = *i;
- lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ if (!this->Bottom.GetState()->GetIsInTryCompile())
+ {
+ lfc.FilePath = converter.Convert(lfc.FilePath, cmOutputConverter::HOME);
+ }
out << " " << lfc << "\n";
}
}