Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add -output-dir and other file handling improvements #412

Merged
merged 14 commits into from
Feb 13, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 10 additions & 2 deletions clang-tools-extra/clangd/tool/ClangdMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,8 +486,16 @@ int main(int argc, char *argv[]) {

// See clang/docs/checkedc/3C/clang-tidy.md#_3c-name-prefix
// NOLINTNEXTLINE(readability-identifier-naming)
_3CInterface _3CInterface(CcOptions, OptionsParser.getSourcePathList(),
&(OptionsParser.getCompilations()));
std::unique_ptr<_3CInterface> _3CInterfacePtr(
_3CInterface::create(CcOptions, OptionsParser.getSourcePathList(),
&(OptionsParser.getCompilations())));
if (!_3CInterfacePtr) {
// _3CInterface::create has already printed an error message. Just exit.
return 1;
}
// See clang/docs/checkedc/3C/clang-tidy.md#_3c-name-prefix
// NOLINTNEXTLINE(readability-identifier-naming)
_3CInterface &_3CInterface = *_3CInterfacePtr;
#else
llvm::cl::ParseCommandLineOptions(
argc, argv,
Expand Down
22 changes: 19 additions & 3 deletions clang/include/clang/3C/3C.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct _3COptions {
bool Verbose;

std::string OutputPostfix;
std::string OutputDir;

std::string ConstraintOutputJson;

Expand All @@ -50,6 +51,7 @@ struct _3COptions {
bool EnablePropThruIType;

std::string BaseDir;
bool AllowSourcesOutsideBaseDir;

bool EnableAllTypes;

Expand Down Expand Up @@ -86,9 +88,19 @@ class _3CInterface {
// Mutex for this interface.
std::mutex InterfaceMutex;

_3CInterface(const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
clang::tooling::CompilationDatabase *CompDB);
// If the parameters are invalid, this function prints an error message to
// stderr and returns null.
//
// There's no way for a constructor to report failure (we do not use
// exceptions), so use a factory method instead. Ideally we'd use an
// "optional" datatype that doesn't force heap allocation, but the only such
// datatype that is accepted in our codebase
// (https://llvm.org/docs/ProgrammersManual.html#fallible-constructors) seems
// too unwieldy to use right now.
static std::unique_ptr<_3CInterface> create(
const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
clang::tooling::CompilationDatabase *CompDB);

// Constraint Building.

Expand Down Expand Up @@ -121,6 +133,10 @@ class _3CInterface {
bool writeConvertedFileToDisk(const std::string &FilePath);

private:
_3CInterface(const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
clang::tooling::CompilationDatabase *CompDB, bool &Failed);

// Are constraints already built?
bool ConstraintsBuilt;
void invalidateAllConstraintsWithReason(Constraint *ConstraintToRemove);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/3C/3CGlobalOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

extern bool Verbose;
extern bool DumpIntermediate;
extern std::string OutputPostfix;
extern std::string OutputDir;
extern bool HandleVARARGS;
extern bool SeperateMultipleFuncDecls;
extern bool EnablePropThruIType;
Expand Down
4 changes: 1 addition & 3 deletions clang/include/clang/3C/RewriteUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,15 +238,13 @@ class ArrayBoundsRewriter {

class RewriteConsumer : public ASTConsumer {
public:
explicit RewriteConsumer(ProgramInfo &I, std::string &OPostfix)
: Info(I), OutputPostfix(OPostfix) {}
explicit RewriteConsumer(ProgramInfo &I) : Info(I) {}

virtual void HandleTranslationUnit(ASTContext &Context);

private:
ProgramInfo &Info;
static std::map<std::string, std::string> ModifiedFuncSignatures;
std::string &OutputPostfix;

// A single header file can be included in multiple translations units. This
// set ensures that the diagnostics for a header file are not emitted each
Expand Down
17 changes: 16 additions & 1 deletion clang/include/clang/3C/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,19 @@ bool hasFunctionBody(clang::Decl *D);

std::string getStorageQualifierString(clang::Decl *D);

bool getAbsoluteFilePath(std::string FileName, std::string &AbsoluteFp);
// Use this version for user input that has not yet been validated.
std::error_code tryGetCanonicalFilePath(const std::string &FileName,
std::string &AbsoluteFp);

// This version asserts success. It may be used for convenience for files we are
// already accessing and thus believe should exist, modulo race conditions and
// the like.
void getCanonicalFilePath(const std::string &FileName, std::string &AbsoluteFp);

// This compares entire path components: it's smart enough to know that "foo.c"
// does not start with "foo". It's not smart about anything else, so you should
// probably put both paths through getCanonicalFilePath first.
bool filePathStartsWith(const std::string &Path, const std::string &Prefix);

bool isNULLExpression(clang::Expr *E, clang::ASTContext &C);

Expand Down Expand Up @@ -147,6 +159,9 @@ bool isCastSafe(clang::QualType DstType, clang::QualType SrcType);

// Check if the provided file path belongs to the input project
// and can be rewritten.
//
// For accurate results, the path must have gone through getCanonicalFilePath.
// Note that the file name of a PersistentSourceLoc is always canonical.
bool canWrite(const std::string &FilePath);

// Check if the provided variable has void as one of its type.
Expand Down
119 changes: 98 additions & 21 deletions clang/lib/3C/3C.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static cl::opt<bool>
bool DumpIntermediate;
bool Verbose;
std::string OutputPostfix;
std::string OutputDir;
std::string ConstraintOutputJson;
std::vector<std::string> AllocatorFunctions;
bool DumpStats;
Expand Down Expand Up @@ -89,7 +90,7 @@ class RewriteAction : public ASTFrontendAction {

virtual std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance &Compiler, StringRef InFile) {
return std::unique_ptr<ASTConsumer>(new T(Info, OutputPostfix));
return std::unique_ptr<ASTConsumer>(new T(Info));
}

private:
Expand Down Expand Up @@ -194,13 +195,27 @@ void runSolver(ProgramInfo &Info, std::set<std::string> &SourceFiles) {
}
}

std::unique_ptr<_3CInterface>
_3CInterface::create(const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
CompilationDatabase *CompDB) {
bool Failed = false;
std::unique_ptr<_3CInterface> _3CInter(
new _3CInterface(CCopt, SourceFileList, CompDB, Failed));
if (Failed) {
return nullptr;
}
return _3CInter;
}

_3CInterface::_3CInterface(const struct _3COptions &CCopt,
const std::vector<std::string> &SourceFileList,
CompilationDatabase *CompDB) {
CompilationDatabase *CompDB, bool &Failed) {

DumpIntermediate = CCopt.DumpIntermediate;
Verbose = CCopt.Verbose;
OutputPostfix = CCopt.OutputPostfix;
OutputDir = CCopt.OutputDir;
ConstraintOutputJson = CCopt.ConstraintOutputJson;
StatsOutputJson = CCopt.StatsOutputJson;
WildPtrInfoJson = CCopt.WildPtrInfoJson;
Expand Down Expand Up @@ -231,35 +246,97 @@ _3CInterface::_3CInterface(const struct _3COptions &CCopt,

ConstraintsBuilt = false;

// Get the absolute path of the base directory.
std::string TmpPath = BaseDir;
getAbsoluteFilePath(BaseDir, TmpPath);
BaseDir = TmpPath;
if (OutputPostfix != "-" && !OutputDir.empty()) {
errs() << "3C initialization error: Cannot use both -output-postfix and "
"-output-dir\n";
Failed = true;
return;
}
if (OutputPostfix == "-" && OutputDir.empty() && SourceFileList.size() > 1) {
errs() << "3C initialization error: Cannot specify more than one input "
"file when output is to stdout\n";
Failed = true;
return;
}

std::string TmpPath;
std::error_code EC;

if (BaseDir.empty()) {
SmallString<256> Cp;
if (std::error_code Ec = sys::fs::current_path(Cp)) {
errs() << "could not get current working dir\n";
assert(false && "Unable to get determine working directory.");
}
BaseDir = ".";
}

// Get the canonical path of the base directory.
TmpPath = BaseDir;
EC = tryGetCanonicalFilePath(BaseDir, TmpPath);
if (EC) {
errs() << "3C initialization error: Failed to canonicalize base directory "
"\"" << BaseDir << "\": " << EC.message() << "\n";
Failed = true;
return;
}
BaseDir = TmpPath;

BaseDir = Cp.str();
if (!OutputDir.empty()) {
// tryGetCanonicalFilePath will fail if the output dir doesn't exist yet, so
// create it first.
EC = llvm::sys::fs::create_directories(OutputDir);
if (EC) {
errs() << "3C initialization error: Failed to create output directory \""
<< OutputDir << "\": " << EC.message() << "\n";
Failed = true;
return;
}
TmpPath = OutputDir;
EC = tryGetCanonicalFilePath(OutputDir, TmpPath);
if (EC) {
errs() << "3C initialization error: Failed to canonicalize output "
"directory \"" << OutputDir << "\": " << EC.message() << "\n";
Failed = true;
return;
}
OutputDir = TmpPath;
}

SourceFiles = SourceFileList;

bool SawInputOutsideBaseDir = false;
for (const auto &S : SourceFiles) {
std::string AbsPath;
if (getAbsoluteFilePath(S, AbsPath))
FilePaths.insert(AbsPath);
EC = tryGetCanonicalFilePath(S, AbsPath);
if (EC) {
errs() << "3C initialization error: Failed to canonicalize source file "
"path \"" << S << "\": " << EC.message() << "\n";
Failed = true;
continue;
}
FilePaths.insert(AbsPath);
if (!filePathStartsWith(AbsPath, BaseDir)) {
errs()
<< "3C initialization "
<< (OutputDir != "" || !CCopt.AllowSourcesOutsideBaseDir ? "error"
: "warning")
<< ": File \"" << AbsPath
<< "\" specified on the command line is outside the base directory\n";
SawInputOutsideBaseDir = true;
}
}
if (SawInputOutsideBaseDir) {
errs() << "The base directory is currently \"" << BaseDir
<< "\" and can be changed with the -base-dir option.\n";
if (OutputDir != "") {
Failed = true;
errs() << "When using -output-dir, input files outside the base "
"directory cannot be handled because there is no way to "
"compute their output paths.\n";
} else if (!CCopt.AllowSourcesOutsideBaseDir) {
Failed = true;
errs() << "You can use the -allow-sources-outside-base-dir option to "
"temporarily downgrade this error to a warning.\n";
}
}

CurrCompDB = CompDB;

if (OutputPostfix == "-" && FilePaths.size() > 1) {
errs() << "If rewriting more than one , can't output to stdout\n";
assert(false && "Rewriting more than one files requires OutputPostfix");
}
}

bool _3CInterface::buildInitialConstraints() {
Expand Down Expand Up @@ -295,15 +372,15 @@ bool _3CInterface::solveConstraints() {
"build constraint before trying to solve them.");
// 2. Solve constraints.
if (Verbose)
outs() << "Solving constraints\n";
errs() << "Solving constraints\n";

if (DumpIntermediate)
GlobalProgramInfo.dump();

runSolver(GlobalProgramInfo, FilePaths);

if (Verbose)
outs() << "Constraints solved\n";
errs() << "Constraints solved\n";

if (WarnRootCause)
GlobalProgramInfo.computeInterimConstraintState(FilePaths);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/3C/ConstraintBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ void ConstraintBuilderConsumer::HandleTranslationUnit(ASTContext &C) {
TV.setProgramInfoTypeVars();

if (Verbose)
outs() << "Done analyzing\n";
errs() << "Done analyzing\n";

Info.exitCompilationUnit();
return;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/3C/PersistentSourceLoc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ PersistentSourceLoc PersistentSourceLoc::mkPSL(clang::SourceRange SR,
std::string FeAbsS = "";
if (Fe != nullptr)
ToConv = Fe->getName();
if (getAbsoluteFilePath(ToConv, FeAbsS))
Fn = sys::path::remove_leading_dotslash(FeAbsS);
getCanonicalFilePath(ToConv, FeAbsS);
Fn = sys::path::remove_leading_dotslash(FeAbsS);
}
PersistentSourceLoc PSL(Fn, FESL.getExpansionLineNumber(),
FESL.getExpansionColumnNumber(), EndCol);
Expand Down
Loading