[cfe-commits] r152018 - in /cfe/trunk: include/clang/Frontend/PreprocessorOptions.h include/clang/Lex/PreprocessingRecord.h include/clang/Lex/Preprocessor.h lib/Frontend/CompilerInstance.cpp lib/Lex/PreprocessingRecord.cpp lib/Lex/Preprocessor.cpp lib/Serialization/ASTReader.cpp unittests/Lex/PreprocessingRecordTest.cpp
Argyrios Kyrtzidis
akyrtzi at gmail.com
Sun Mar 4 21:48:17 PST 2012
Author: akirtzidis
Date: Sun Mar 4 23:48:17 2012
New Revision: 152018
URL: http://llvm.org/viewvc/llvm-project?rev=152018&view=rev
Log:
[preprocessor] Enhance PreprocessingRecord to keep track of locations of conditional directives.
Introduce PreprocessingRecord::rangeIntersectsConditionalDirective() which returns
true if a given range intersects with a conditional directive block.
Added:
cfe/trunk/unittests/Lex/PreprocessingRecordTest.cpp
Modified:
cfe/trunk/include/clang/Frontend/PreprocessorOptions.h
cfe/trunk/include/clang/Lex/PreprocessingRecord.h
cfe/trunk/include/clang/Lex/Preprocessor.h
cfe/trunk/lib/Frontend/CompilerInstance.cpp
cfe/trunk/lib/Lex/PreprocessingRecord.cpp
cfe/trunk/lib/Lex/Preprocessor.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
Modified: cfe/trunk/include/clang/Frontend/PreprocessorOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/PreprocessorOptions.h?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/PreprocessorOptions.h (original)
+++ cfe/trunk/include/clang/Frontend/PreprocessorOptions.h Sun Mar 4 23:48:17 2012
@@ -49,6 +49,10 @@
unsigned DetailedRecord : 1; /// Whether we should maintain a detailed
/// record of all macro definitions and
/// expansions.
+ unsigned DetailedRecordConditionalDirectives : 1; /// Whether in the
+ /// preprocessing record we should also keep
+ /// track of locations of conditional directives
+ /// in non-system files.
/// The implicit PCH included at the start of the translation unit, or empty.
std::string ImplicitPCHInclude;
@@ -158,6 +162,7 @@
public:
PreprocessorOptions() : UsePredefines(true), DetailedRecord(false),
+ DetailedRecordConditionalDirectives(false),
DisablePCHValidation(false), DisableStatCache(false),
DumpDeserializedPCHDecls(false),
PrecompiledPreambleBytes(0, true),
Modified: cfe/trunk/include/clang/Lex/PreprocessingRecord.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PreprocessingRecord.h?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/PreprocessingRecord.h (original)
+++ cfe/trunk/include/clang/Lex/PreprocessingRecord.h Sun Mar 4 23:48:17 2012
@@ -17,6 +17,7 @@
#include "clang/Lex/PPCallbacks.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/IdentifierTable.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Allocator.h"
@@ -299,6 +300,44 @@
/// and are referenced by the iterator using negative indices.
std::vector<PreprocessedEntity *> LoadedPreprocessedEntities;
+ bool RecordCondDirectives;
+ unsigned CondDirectiveNextIdx;
+ SmallVector<unsigned, 6> CondDirectiveStack;
+
+ class CondDirectiveLoc {
+ SourceLocation Loc;
+ unsigned Idx;
+
+ public:
+ CondDirectiveLoc(SourceLocation Loc, unsigned Idx) : Loc(Loc), Idx(Idx) {}
+
+ SourceLocation getLoc() const { return Loc; }
+ unsigned getIdx() const { return Idx; }
+
+ class Comp {
+ SourceManager &SM;
+ public:
+ explicit Comp(SourceManager &SM) : SM(SM) {}
+ bool operator()(const CondDirectiveLoc &LHS,
+ const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc());
+ }
+ bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) {
+ return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS);
+ }
+ bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) {
+ return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc());
+ }
+ };
+ };
+
+ typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy;
+ /// \brief The locations of conditional directives in source order.
+ CondDirectiveLocsTy CondDirectiveLocs;
+
+ void addCondDirectiveLoc(CondDirectiveLoc DirLoc);
+ unsigned findCondDirectiveIdx(SourceLocation Loc) const;
+
/// \brief Global (loaded or local) ID for a preprocessed entity.
/// Negative values are used to indicate preprocessed entities
/// loaded from the external source while non-negative values are used to
@@ -349,7 +388,7 @@
public:
/// \brief Construct a new preprocessing record.
- explicit PreprocessingRecord(SourceManager &SM);
+ PreprocessingRecord(SourceManager &SM, bool RecordConditionalDirectives);
/// \brief Allocate memory in the preprocessing record.
void *Allocate(unsigned Size, unsigned Align = 8) {
@@ -517,7 +556,25 @@
/// \brief Add a new preprocessed entity to this record.
void addPreprocessedEntity(PreprocessedEntity *Entity);
-
+
+ /// \brief Returns true if this PreprocessingRecord is keeping track of
+ /// conditional directives locations.
+ bool isRecordingConditionalDirectives() const {
+ return RecordCondDirectives;
+ }
+
+ /// \brief Returns true if the given range intersects with a conditional
+ /// directive. if a #if/#endif block is fully contained within the range,
+ /// this function will return false.
+ bool rangeIntersectsConditionalDirective(SourceRange Range) const;
+
+ /// \brief Returns true if the given locations are in different regions,
+ /// separated by conditional directive blocks.
+ bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS,
+ SourceLocation RHS) const {
+ return findCondDirectiveIdx(LHS) != findCondDirectiveIdx(RHS);
+ }
+
/// \brief Set the external source for preprocessed entities.
void SetExternalSource(ExternalPreprocessingRecordSource &Source);
@@ -530,6 +587,7 @@
/// \c MacroInfo.
MacroDefinition *findMacroDefinition(const MacroInfo *MI);
+ private:
virtual void MacroExpands(const Token &Id, const MacroInfo* MI,
SourceRange Range);
virtual void MacroDefined(const Token &Id, const MacroInfo *MI);
@@ -542,8 +600,14 @@
SourceLocation EndLoc,
StringRef SearchPath,
StringRef RelativePath);
+ virtual void If(SourceLocation Loc, SourceRange ConditionRange);
+ virtual void Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc);
+ virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok);
+ virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok);
+ virtual void Else(SourceLocation Loc, SourceLocation IfLoc);
+ virtual void Endif(SourceLocation Loc, SourceLocation IfLoc);
- private:
/// \brief Cached result of the last \see getPreprocessedEntitiesInRange
/// query.
struct {
Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Sun Mar 4 23:48:17 2012
@@ -512,7 +512,7 @@
/// \brief Create a new preprocessing record, which will keep track of
/// all macro expansions, macro definitions, etc.
- void createPreprocessingRecord();
+ void createPreprocessingRecord(bool RecordConditionalDirectives);
/// EnterMainSourceFile - Enter the specified FileID as the main source file,
/// which implicitly adds the builtin defines etc.
Modified: cfe/trunk/lib/Frontend/CompilerInstance.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInstance.cpp?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInstance.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInstance.cpp Sun Mar 4 23:48:17 2012
@@ -257,7 +257,7 @@
}
if (PPOpts.DetailedRecord)
- PP->createPreprocessingRecord();
+ PP->createPreprocessingRecord(PPOpts.DetailedRecordConditionalDirectives);
InitializePreprocessor(*PP, PPOpts, getHeaderSearchOpts(), getFrontendOpts());
Modified: cfe/trunk/lib/Lex/PreprocessingRecord.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PreprocessingRecord.cpp?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PreprocessingRecord.cpp (original)
+++ cfe/trunk/lib/Lex/PreprocessingRecord.cpp Sun Mar 4 23:48:17 2012
@@ -37,9 +37,14 @@
this->FileName = StringRef(Memory, FileName.size());
}
-PreprocessingRecord::PreprocessingRecord(SourceManager &SM)
- : SourceMgr(SM), ExternalSource(0)
+PreprocessingRecord::PreprocessingRecord(SourceManager &SM,
+ bool RecordConditionalDirectives)
+ : SourceMgr(SM),
+ RecordCondDirectives(RecordConditionalDirectives), CondDirectiveNextIdx(0),
+ ExternalSource(0)
{
+ if (RecordCondDirectives)
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
}
/// \brief Returns a pair of [Begin, End) iterators of preprocessed entities
@@ -397,6 +402,95 @@
addPreprocessedEntity(ID);
}
+bool PreprocessingRecord::rangeIntersectsConditionalDirective(
+ SourceRange Range) const {
+ if (Range.isInvalid())
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Range.getBegin(), CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return false;
+
+ if (SourceMgr.isBeforeInTranslationUnit(Range.getEnd(), low->getLoc()))
+ return false;
+
+ CondDirectiveLocsTy::const_iterator
+ upp = std::upper_bound(low, CondDirectiveLocs.end(),
+ Range.getEnd(), CondDirectiveLoc::Comp(SourceMgr));
+ unsigned uppIdx;
+ if (upp != CondDirectiveLocs.end())
+ uppIdx = upp->getIdx();
+ else
+ uppIdx = 0;
+
+ return low->getIdx() != uppIdx;
+}
+
+unsigned PreprocessingRecord::findCondDirectiveIdx(SourceLocation Loc) const {
+ if (Loc.isInvalid())
+ return 0;
+
+ CondDirectiveLocsTy::const_iterator
+ low = std::lower_bound(CondDirectiveLocs.begin(), CondDirectiveLocs.end(),
+ Loc, CondDirectiveLoc::Comp(SourceMgr));
+ if (low == CondDirectiveLocs.end())
+ return 0;
+ return low->getIdx();
+}
+
+void PreprocessingRecord::addCondDirectiveLoc(CondDirectiveLoc DirLoc) {
+ // Ignore directives in system headers.
+ if (SourceMgr.isInSystemHeader(DirLoc.getLoc()))
+ return;
+
+ assert(CondDirectiveLocs.empty() ||
+ SourceMgr.isBeforeInTranslationUnit(CondDirectiveLocs.back().getLoc(),
+ DirLoc.getLoc()));
+ CondDirectiveLocs.push_back(DirLoc);
+}
+
+void PreprocessingRecord::If(SourceLocation Loc, SourceRange ConditionRange) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Ifdef(SourceLocation Loc, const Token &MacroNameTok) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Ifndef(SourceLocation Loc,const Token &MacroNameTok) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ CondDirectiveStack.push_back(CondDirectiveNextIdx++);
+ }
+}
+
+void PreprocessingRecord::Elif(SourceLocation Loc, SourceRange ConditionRange,
+ SourceLocation IfLoc) {
+ if (RecordCondDirectives)
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+}
+
+void PreprocessingRecord::Else(SourceLocation Loc, SourceLocation IfLoc) {
+ if (RecordCondDirectives)
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+}
+
+void PreprocessingRecord::Endif(SourceLocation Loc, SourceLocation IfLoc) {
+ if (RecordCondDirectives) {
+ addCondDirectiveLoc(CondDirectiveLoc(Loc, CondDirectiveStack.back()));
+ assert(!CondDirectiveStack.empty());
+ CondDirectiveStack.pop_back();
+ }
+}
+
size_t PreprocessingRecord::getTotalMemory() const {
return BumpAlloc.getTotalMemory()
+ llvm::capacity_in_bytes(MacroDefinitions)
Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Sun Mar 4 23:48:17 2012
@@ -654,10 +654,11 @@
CodeCompletionHandler::~CodeCompletionHandler() { }
-void Preprocessor::createPreprocessingRecord() {
+void Preprocessor::createPreprocessingRecord(bool RecordConditionalDirectives) {
if (Record)
return;
- Record = new PreprocessingRecord(getSourceManager());
+ Record = new PreprocessingRecord(getSourceManager(),
+ RecordConditionalDirectives);
addPPCallbacks(Record);
}
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=152018&r1=152017&r2=152018&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Sun Mar 4 23:48:17 2012
@@ -1744,7 +1744,7 @@
= F.PreprocessorDetailCursor.GetCurrentBitNo();
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord();
+ PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
break;
@@ -2288,7 +2288,7 @@
unsigned StartingID;
if (!PP.getPreprocessingRecord())
- PP.createPreprocessingRecord();
+ PP.createPreprocessingRecord(/*RecordConditionalDirectives=*/false);
if (!PP.getPreprocessingRecord()->getExternalSource())
PP.getPreprocessingRecord()->SetExternalSource(*this);
StartingID
Added: cfe/trunk/unittests/Lex/PreprocessingRecordTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Lex/PreprocessingRecordTest.cpp?rev=152018&view=auto
==============================================================================
--- cfe/trunk/unittests/Lex/PreprocessingRecordTest.cpp (added)
+++ cfe/trunk/unittests/Lex/PreprocessingRecordTest.cpp Sun Mar 4 23:48:17 2012
@@ -0,0 +1,139 @@
+//===- unittests/Lex/PreprocessingRecordTest.cpp - PreprocessingRecord tests =//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessingRecord.h"
+#include "llvm/Config/config.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace clang;
+
+namespace {
+
+// The test fixture.
+class PreprocessingRecordTest : public ::testing::Test {
+protected:
+ PreprocessingRecordTest()
+ : FileMgr(FileMgrOpts),
+ DiagID(new DiagnosticIDs()),
+ Diags(DiagID, new IgnoringDiagConsumer()),
+ SourceMgr(Diags, FileMgr) {
+ TargetOpts.Triple = "x86_64-apple-darwin11.1.0";
+ Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+ }
+
+ FileSystemOptions FileMgrOpts;
+ FileManager FileMgr;
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+ DiagnosticsEngine Diags;
+ SourceManager SourceMgr;
+ LangOptions LangOpts;
+ TargetOptions TargetOpts;
+ IntrusiveRefCntPtr<TargetInfo> Target;
+};
+
+class VoidModuleLoader : public ModuleLoader {
+ virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
+ Module::NameVisibilityKind Visibility,
+ bool IsInclusionDirective) {
+ return 0;
+ }
+};
+
+TEST_F(PreprocessingRecordTest, PPRecAPI) {
+ const char *source =
+ "0 1\n"
+ "#if 1\n"
+ "2\n"
+ "#ifndef BB\n"
+ "3 4\n"
+ "#else\n"
+ "#endif\n"
+ "5\n"
+ "#endif\n"
+ "6\n"
+ "#if 1\n"
+ "7\n"
+ "#if 1\n"
+ "#endif\n"
+ "8\n"
+ "#endif\n"
+ "9\n";
+
+ MemoryBuffer *buf = MemoryBuffer::getMemBuffer(source);
+ SourceMgr.createMainFileIDForMemBuffer(buf);
+
+ VoidModuleLoader ModLoader;
+ HeaderSearch HeaderInfo(FileMgr, Diags, LangOpts, Target.getPtr());
+ Preprocessor PP(Diags, LangOpts,
+ Target.getPtr(),
+ SourceMgr, HeaderInfo, ModLoader,
+ /*IILookup =*/ 0,
+ /*OwnsHeaderSearch =*/false,
+ /*DelayInitialization =*/ false);
+ PP.createPreprocessingRecord(true);
+ PP.EnterMainSourceFile();
+
+ std::vector<Token> toks;
+ while (1) {
+ Token tok;
+ PP.Lex(tok);
+ if (tok.is(tok::eof))
+ break;
+ toks.push_back(tok);
+ }
+
+ // Make sure we got the tokens that we expected.
+ ASSERT_EQ(10U, toks.size());
+
+ PreprocessingRecord &PPRec = *PP.getPreprocessingRecord();
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[1].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[2].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[3].getLocation(), toks[4].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[1].getLocation(), toks[5].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[6].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[5].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[6].getLocation())));
+ EXPECT_TRUE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[2].getLocation(), toks[8].getLocation())));
+ EXPECT_FALSE(PPRec.rangeIntersectsConditionalDirective(
+ SourceRange(toks[0].getLocation(), toks[9].getLocation())));
+
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[0].getLocation(), toks[2].getLocation()));
+ EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[3].getLocation(), toks[4].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[1].getLocation(), toks[5].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[2].getLocation(), toks[0].getLocation()));
+ EXPECT_FALSE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[4].getLocation(), toks[3].getLocation()));
+ EXPECT_TRUE(PPRec.areInDifferentConditionalDirectiveRegion(
+ toks[5].getLocation(), toks[1].getLocation()));
+}
+
+} // anonymous namespace
More information about the cfe-commits
mailing list