Skip to content
Snippets Groups Projects
Commit 778bf678 authored by Heldmann, Tim's avatar Heldmann, Tim
Browse files

Enable experimental support for macros, improve pragma hadling resilience

parent 50a954bf
Branches
Tags 0.5.0
No related merge requests found
......@@ -19,7 +19,7 @@ class PreprocessorExtract : public clang::PPCallbacks {
public:
PreprocessorExtract(clang::SourceManager &sm, std::vector<ExtractionBlock> &includes,
std::vector<ExtractionBlock> &macros, std::vector<ExtractionBlock> &pragmas) : sourceManager(
sm), includes(includes), macros(macros), pragmas(pragmas) {}
sm), includes(includes), macros(macros), pragmas(pragmas), languageOption(clang::LangOptions()) {}
inline void InclusionDirective(clang::SourceLocation HashLoc, const clang::Token &IncludeTok,
clang::StringRef FileName, bool IsAngled,
......@@ -43,6 +43,8 @@ public:
inline void PragmaDirective(clang::SourceLocation Loc,
clang::PragmaIntroducerKind Introducer) override;
void Defined(const clang::Token &MacroNameTok, const clang::MacroDefinition &MD, clang::SourceRange Range) override;
private:
std::vector<ExtractionBlock> &includes;
std::vector<ExtractionBlock> &macros;
......@@ -50,7 +52,9 @@ private:
//FixMe: make macroBeginStack with beginSourceLoc to save space
std::stack<ExtractionBlock> macroNestingStack;
clang::SourceManager &sourceManager;
clang::LangOptions languageOption;
void MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *MD);
};
#endif //CTUAPEX_PREPROCESSOREXTRACT_H
//
// Created by tim on 21.12.23.
//
#include <clang/Lex/Preprocessor.h>
#include "PreprocessorExtract.h"
......@@ -23,7 +24,12 @@ void PreprocessorExtract::Ifdef(clang::SourceLocation Loc, const clang::Token &M
}
void PreprocessorExtract::Ifndef(clang::SourceLocation Loc, const clang::Token &MacroNameTok,
const clang::MacroDefinition &MD) { Ifdef(Loc, MacroNameTok, MD); };
const clang::MacroDefinition &MD) {
if (!sourceManager.isInMainFile(Loc)) {
return;
}
Ifdef(Loc, MacroNameTok, MD);
};
void PreprocessorExtract::Endif(clang::SourceLocation Loc, clang::SourceLocation IfLoc) {
if (!sourceManager.isInMainFile(Loc)) {
......@@ -40,7 +46,7 @@ void PreprocessorExtract::Endif(clang::SourceLocation Loc, clang::SourceLocation
macro.end = Loc;
clang::SourceRange sourceRange(macro.begin, macro.end);
clang::CharSourceRange charSourceRange(sourceRange, true);
macro.contents = "#" + clang::Lexer::getSourceText(charSourceRange, sourceManager, clang::LangOptions()).str();
macro.contents = "#" + clang::Lexer::getSourceText(charSourceRange, sourceManager, languageOption).str();
macros.push_back(macro);
}
......@@ -49,20 +55,37 @@ inline void PreprocessorExtract::PragmaDirective(clang::SourceLocation Loc,
if (!sourceManager.isInMainFile(Loc)) {
return;
}
Loc.printToString(sourceManager);
//We only get the start of the pragma
clang::CharSourceRange charSourceRange({Loc, Loc.getLocWithOffset(0)}, true);
clang::CharSourceRange charSourceRange = {{Loc, Loc}, true};
llvm::StringRef text = clang::Lexer::getSourceText(charSourceRange, sourceManager, languageOption);
//if the text we get from the lexer is empty, it means that the pragma is not at the location we expect it to be
if(text.empty()){
//I assume that this must mean it was introduced via the preprocessor itself
//Therefore, the location should contain the Spelling location of the macro that introduced the pragma
//This test is definitly ugly, but i didn't manage to get the spelling otherwise
assert(Loc.printToString(sourceManager).find("<Spelling=")!=std::string::npos);
//If this is the case, then we allready handle this pragma in the macro defintion extraction and can return safely
//(the contents of the pragma will already be contained inside the extraction block of the parent maco
return;
}
//We move forward until we encounter a newline, which finishes the pragma,
// or enounter a \ followed by a newline, which means the pragma goes on in the next line
int i=0;
while(!clang::Lexer::getSourceText({{Loc, Loc.getLocWithOffset(i)}, true}, sourceManager, clang::LangOptions()).endswith("\n") ||
clang::Lexer::getSourceText({{Loc, Loc.getLocWithOffset(i)}, true}, sourceManager, clang::LangOptions()).endswith("\\\n") ) {
i++;
for (int i = 0; !text.endswith("\n") || text.endswith("\\\n"); i++) {
//only reset the assumed end of the sourcerange to keep object intact
llvm::outs() << text << "\n";
charSourceRange.setEnd(Loc.getLocWithOffset(i));
text = clang::Lexer::getSourceText(charSourceRange, sourceManager, languageOption);
assert(i < 5000);//This is for debugging
}
ExtractionBlock res;
res.begin = Loc;
res.end = charSourceRange.getEnd();
res.contents = clang::Lexer::getSourceText({{Loc, Loc.getLocWithOffset(i)}, true}, sourceManager, clang::LangOptions());
res.contents = clang::Lexer::getSourceText(charSourceRange, sourceManager, languageOption);
pragmas.push_back(res);
}
......@@ -74,7 +97,33 @@ void PreprocessorExtract::InclusionDirective(clang::SourceLocation HashLoc, cons
const clang::Module *Imported,
clang::SrcMgr::CharacteristicKind FileType) {
//Note: we currently exclude headers only by name, we could also compare them according to their sourcerange
if (sourceManager.isInMainFile(HashLoc)) {
includes.emplace_back(HashLoc, FilenameRange.getEnd(), "#include \"" + FileName.str() + "\"");
if (!sourceManager.isInMainFile(HashLoc)) {
return;
}
includes.emplace_back(HashLoc, FilenameRange.getEnd(), "#include \"" + FileName.str() + "\"");
}
void PreprocessorExtract::Defined(const clang::Token &MacroNameTok, const clang::MacroDefinition &MD,
clang::SourceRange Range) {
//This has not yet been needed, if we find a defined-clause in the main file, we have a problem
if (sourceManager.isInMainFile(Range.getBegin())) {
assert(false);
}
}
void PreprocessorExtract::MacroDefined(const clang::Token &MacroNameTok, const clang::MacroDirective *MD) {
if (!sourceManager.isInMainFile(MacroNameTok.getLocation())) {
return;
}
//We are not interested in compiler defined internal macro definition
//We can not rely on MD->getMacroInfo()->isBuiltinMacro() as it fails to trigger on built-in macros!?
if (MacroNameTok.getLocation().printToString(sourceManager).find("<built-in>") != std::string::npos) {
return;
}
ExtractionBlock res;
res.begin = MD->getMacroInfo()->getDefinitionLoc();
res.end = MD->getMacroInfo()->getDefinitionEndLoc();
res.contents = clang::Lexer::getSourceText({{res.begin, res.end}, true}, sourceManager, languageOption);
macros.push_back(res);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment