aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Frontend/FrontendAction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Frontend/FrontendAction.cpp')
-rw-r--r--clang/lib/Frontend/FrontendAction.cpp164
1 files changed, 125 insertions, 39 deletions
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 1d82fc7..a7d6a068 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -9,6 +9,7 @@
#include "clang/Frontend/FrontendAction.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/DiagnosticOptions.h"
@@ -39,6 +40,7 @@
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/BuryPointer.h"
#include "llvm/Support/ErrorHandling.h"
@@ -82,17 +84,29 @@ public:
if (!IsCollectingDecls)
return;
if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) ||
- isa<NamespaceDecl>(D)) {
+ isa<NamespaceDecl>(D) || isa<ExportDecl>(D)) {
// These decls cover a lot of nested declarations that might not be used,
// reducing the granularity and making the output less useful.
return;
}
- if (auto *DC = D->getDeclContext(); !DC || !DC->isFileContext()) {
- // We choose to work at namespace level to reduce complexity and the
- // number of cases we care about.
+ if (isa<ParmVarDecl>(D)) {
+ // Parameters are covered by their functions.
return;
}
+ auto *DC = D->getLexicalDeclContext();
+ if (!DC || !shouldIncludeDeclsIn(DC))
+ return;
+
PendingDecls.push_back(D);
+ for (; (isa<ExportDecl>(DC) || isa<NamespaceDecl>(DC)) &&
+ ProcessedDeclContexts.insert(DC).second;
+ DC = DC->getLexicalParent()) {
+ // Add any interesting decl contexts that we have not seen before.
+ // Note that we filter them out from DeclRead as that would include all
+ // redeclarations of namespaces, potentially those that do not have any
+ // imported declarations.
+ PendingDecls.push_back(cast<Decl>(DC));
+ }
}
struct Position {
@@ -141,23 +155,25 @@ public:
OptionalFileEntryRef Ref;
};
llvm::DenseMap<const FileEntry *, FileData> FileToRanges;
+
for (const Decl *D : PendingDecls) {
- CharSourceRange R = SM.getExpansionRange(D->getSourceRange());
- if (!R.isValid())
- continue;
+ for (CharSourceRange R : getRangesToMark(D)) {
+ if (!R.isValid())
+ continue;
- auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin()));
- if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd()))) {
- // Such cases are rare and difficult to handle.
- continue;
- }
+ auto *F = SM.getFileEntryForID(SM.getFileID(R.getBegin()));
+ if (F != SM.getFileEntryForID(SM.getFileID(R.getEnd()))) {
+ // Such cases are rare and difficult to handle.
+ continue;
+ }
- auto &Data = FileToRanges[F];
- if (!Data.Ref)
- Data.Ref = SM.getFileEntryRefForID(SM.getFileID(R.getBegin()));
- Data.FromTo.push_back(
- {Position::GetBeginSpelling(SM, R),
- Position::GetEndSpelling(SM, R, D->getLangOpts())});
+ auto &Data = FileToRanges[F];
+ if (!Data.Ref)
+ Data.Ref = SM.getFileEntryRefForID(SM.getFileID(R.getBegin()));
+ Data.FromTo.push_back(
+ {Position::GetBeginSpelling(SM, R),
+ Position::GetEndSpelling(SM, R, D->getLangOpts())});
+ }
}
// To simplify output, merge consecutive and intersecting ranges.
@@ -188,10 +204,65 @@ public:
private:
std::vector<const Decl *> PendingDecls;
+ llvm::SmallPtrSet<const DeclContext *, 0> ProcessedDeclContexts;
bool IsCollectingDecls = true;
const SourceManager &SM;
std::unique_ptr<llvm::raw_ostream> OS;
+ static bool shouldIncludeDeclsIn(const DeclContext *DC) {
+ assert(DC && "DC is null");
+ // We choose to work at namespace level to reduce complexity and the number
+ // of cases we care about.
+ // We still need to carefully handle composite declarations like
+ // `ExportDecl`.
+ for (; DC; DC = DC->getLexicalParent()) {
+ if (DC->isFileContext())
+ return true;
+ if (isa<ExportDecl>(DC))
+ continue; // Depends on the parent.
+ return false;
+ }
+ llvm_unreachable("DeclContext chain must end with a translation unit");
+ }
+
+ llvm::SmallVector<CharSourceRange, 2> getRangesToMark(const Decl *D) {
+ if (auto *ED = dyn_cast<ExportDecl>(D)) {
+ if (!ED->hasBraces())
+ return {SM.getExpansionRange(ED->getExportLoc())};
+
+ return {SM.getExpansionRange(SourceRange(
+ ED->getExportLoc(),
+ lexForLBrace(ED->getExportLoc(), D->getLangOpts()))),
+ SM.getExpansionRange(ED->getRBraceLoc())};
+ }
+
+ auto *NS = dyn_cast<NamespaceDecl>(D);
+ if (!NS)
+ return {SM.getExpansionRange(D->getSourceRange())};
+
+ SourceLocation LBraceLoc;
+ if (NS->isAnonymousNamespace()) {
+ LBraceLoc = NS->getLocation();
+ } else {
+ // Start with the location of the identifier.
+ SourceLocation TokenBeforeLBrace = NS->getLocation();
+ if (NS->hasAttrs()) {
+ for (auto *A : NS->getAttrs()) {
+ // But attributes may go after it.
+ if (SM.isBeforeInTranslationUnit(TokenBeforeLBrace,
+ A->getRange().getEnd())) {
+ // Give up, the attributes are often coming from macros and we
+ // cannot skip them reliably.
+ return {};
+ }
+ }
+ }
+ LBraceLoc = lexForLBrace(TokenBeforeLBrace, D->getLangOpts());
+ }
+ return {SM.getExpansionRange(SourceRange(NS->getBeginLoc(), LBraceLoc)),
+ SM.getExpansionRange(NS->getRBraceLoc())};
+ }
+
void printJson(llvm::ArrayRef<RequiredRanges> Result) {
*OS << "{\n";
*OS << R"( "required_ranges": [)" << "\n";
@@ -226,6 +297,22 @@ private:
}
*OS << " ]\n";
*OS << "}\n";
+
+ OS->flush();
+ }
+
+ SourceLocation lexForLBrace(SourceLocation TokenBeforeLBrace,
+ const LangOptions &LangOpts) {
+ // Now skip one token, the next should be the lbrace.
+ Token Tok;
+ if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) ||
+ Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) ||
+ Tok.getKind() != tok::l_brace) {
+ // On error or if we did not find the token we expected, avoid marking
+ // everything inside the namespace as used.
+ return SourceLocation();
+ }
+ return Tok.getLocation();
}
};
@@ -763,11 +850,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// If we're replaying the build of an AST file, import it and set up
// the initial state from its build.
if (ReplayASTFile) {
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags = CI.getDiagnosticsPtr();
// The AST unit populates its own diagnostics engine rather than ours.
- IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine(
- Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions()));
+ auto ASTDiags = llvm::makeIntrusiveRefCnt<DiagnosticsEngine>(
+ Diags->getDiagnosticIDs(), Diags->getDiagnosticOptions());
ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
// FIXME: What if the input is a memory buffer?
@@ -787,7 +874,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Set the shared objects, these are reset when we finish processing the
// file, otherwise the CompilerInstance will happily destroy them.
- CI.setFileManager(&AST->getFileManager());
+ CI.setFileManager(AST->getFileManagerPtr());
CI.createSourceManager(CI.getFileManager());
CI.getSourceManager().initializeForReplay(AST->getSourceManager());
@@ -835,7 +922,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
assert(hasASTFileSupport() &&
"This action does not have AST file support!");
- IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags = CI.getDiagnosticsPtr();
// FIXME: What if the input is a memory buffer?
StringRef InputFile = Input.getFile();
@@ -854,13 +941,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Set the shared objects, these are reset when we finish processing the
// file, otherwise the CompilerInstance will happily destroy them.
- CI.setFileManager(&AST->getFileManager());
- CI.setSourceManager(&AST->getSourceManager());
+ CI.setFileManager(AST->getFileManagerPtr());
+ CI.setSourceManager(AST->getSourceManagerPtr());
CI.setPreprocessor(AST->getPreprocessorPtr());
Preprocessor &PP = CI.getPreprocessor();
PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
PP.getLangOpts());
- CI.setASTContext(&AST->getASTContext());
+ CI.setASTContext(AST->getASTContextPtr());
setCurrentInput(Input, std::move(AST));
@@ -1114,11 +1201,12 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
- IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
+ IntrusiveRefCntPtr<ExternalSemaSource> source;
+ IntrusiveRefCntPtr<ASTReader> FinalReader;
source = createChainedIncludesSource(CI, FinalReader);
if (!source)
return false;
- CI.setASTReader(static_cast<ASTReader *>(FinalReader.get()));
+ CI.setASTReader(FinalReader);
CI.getASTContext().setExternalSource(source);
} else if (CI.getLangOpts().Modules ||
!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
@@ -1194,23 +1282,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// provides the layouts from that file.
if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
- IntrusiveRefCntPtr<ExternalASTSource>
- Override(new LayoutOverrideSource(
- CI.getFrontendOpts().OverrideRecordLayoutsFile));
+ auto Override = llvm::makeIntrusiveRefCnt<LayoutOverrideSource>(
+ CI.getFrontendOpts().OverrideRecordLayoutsFile);
CI.getASTContext().setExternalSource(Override);
}
// Setup HLSL External Sema Source
if (CI.getLangOpts().HLSL && CI.hasASTContext()) {
- IntrusiveRefCntPtr<ExternalSemaSource> HLSLSema(
- new HLSLExternalSemaSource());
- if (auto *SemaSource = dyn_cast_if_present<ExternalSemaSource>(
- CI.getASTContext().getExternalSource())) {
- IntrusiveRefCntPtr<ExternalSemaSource> MultiSema(
- new MultiplexExternalSemaSource(SemaSource, HLSLSema.get()));
- CI.getASTContext().setExternalSource(MultiSema);
+ auto HLSLSema = llvm::makeIntrusiveRefCnt<HLSLExternalSemaSource>();
+ if (auto SemaSource = dyn_cast_if_present<ExternalSemaSource>(
+ CI.getASTContext().getExternalSourcePtr())) {
+ auto MultiSema = llvm::makeIntrusiveRefCnt<MultiplexExternalSemaSource>(
+ std::move(SemaSource), std::move(HLSLSema));
+ CI.getASTContext().setExternalSource(std::move(MultiSema));
} else
- CI.getASTContext().setExternalSource(HLSLSema);
+ CI.getASTContext().setExternalSource(std::move(HLSLSema));
}
FailureCleanup.release();