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

Implement ability for project properties to suppress and elevate warnings #1928

Merged
merged 3 commits into from
Apr 4, 2017

Conversation

jeffkl
Copy link
Contributor

@jeffkl jeffkl commented Mar 30, 2017

Introduce MSBuildTreatWarningsAsErrors property that when set to true will treat all warnings as errors when building a project.
Introduce MSBuildWarningsAsErrors property which is a semicolon delmited list of warning codes to treat as errors when building a project.
Introduce MSBuildWarningsAsMessages property which is a semicolon delimited list of warning codes to treat as low importance messages.

This allows users to control warnings at the project level via standard MSBuild properties. They can be set in a project, an import, or from the command-line.

The limitation here is that the warnings can only include ones that occur during a build. This is because the properties are not read until after parsing so warnings generated during parse/evaluation happen too soon. For these warnings, users will only be able to treat them as errors/messages with the /WarnAsError and /WarnAsMessage command-line arguments.

Closes #1886

@jeffkl
Copy link
Contributor Author

jeffkl commented Mar 30, 2017

FYI @jaredpar

@jaredpar
Copy link
Member

Nice!

@@ -1079,6 +1080,10 @@ private void SetProjectCurrentDirectory()

_projectLoggingContext = _nodeLoggingContext.LogProjectStarted(_requestEntry);

// Now that the project has started, parse a few known properties which indicate warning codes to treat as errors or messages
//
ConfigureWarningsAsErrorsAndMessages();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this is the only place where MSBuild evaluates a project file during build. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you foresee any performance degradation by adding this call? I assumed it was safe since the project has "started" building...

Copy link
Contributor

@cdmihai cdmihai Apr 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It runs once for each project evaluation, so it should scale linearly with number of evaluations (Project nr x (msbuild tasks per project)). I think ~5000 projects is considered "outlier big".

Copy link
Contributor

@cdmihai cdmihai Apr 3, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Offline discussion: My bad, this actually happens only once per node.


// Ensure everything that is required is available at this time
//
if (project != null && buildEventContext != null && loggingService != null && buildEventContext.ProjectInstanceId != BuildEventContext.InvalidProjectInstanceId)
Copy link
Contributor

@cdmihai cdmihai Mar 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check this works on a p2p node as well. Nodes initially assign a temp project ID (maybe the invalid one?) and I don't remember whether they get the global ID before or after they evaluate the project.

}
else
{
ISet<string> warningsAsErrors = ParseWarningCodes(project.GetPropertyValue(MSBuildConstants.WarningsAsErrors));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the user defines TreatWarningsAsErrors=True and also WarningsAsErrors="a;b;c;d"? I'd expect msbuild to treat only the specified warnings as errors, as opposed to ignoring the warning list.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At the moment, MSBuildTreatWarningsAsErrors will override any list. This is the same way that argument works for the compilers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, didn't know. Go with the same behaviour as the compilers then. Except for the warning list separator :)

}

return new HashSet<string>(
warnings.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd only keep semicolons, as they are the msbuild approved way of separating things. And then maybe use ExpressionShredder.SplitSemiColonSeparatedList

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


public void AddWarningsAsMessages(int projectInstanceId, ISet<string> codes)
{
lock (_lockObject)
Copy link
Contributor

@cdmihai cdmihai Mar 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are using a concurrent dictionary, rather than locking, you can use a thread safe Lazy to initialize it, and then not use the external lock when using it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this out but hit a snag. I'm using the state of null as an indicator if any warnings should be treated as an error/message. If I use a Lazy<T>, then I would have to expose it as such so that the caller can determine if HasValue is true. Leaving it the way it is, the property remains of type IDictionary and a simple null check is done. If its okay to have IBuildEventSink have a property that is of type Lazy<T>, then I'll do it.

}
}

ISet<string> warningsAsMessages = ParseWarningCodes(project.GetPropertyValue(MSBuildConstants.WarningsAsMessages));
Copy link
Contributor

@cdmihai cdmihai Mar 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the user has the same warning code as both a message and an error? I'd expect error to win, on the grounds that errors are more serious than messages. Or maybe emit a warning saying that both were specified and the intent is ambiguous. The user can then treat that new warning as a message (but hopefully not as an error as well) :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suppressing a warning overrides elevating one. This is so you can treat all warnings as errors but still turn a few of them off.

{
// This only applies if the user specified /warnaserror from the command-line or added an empty set through the object model
//
if (WarningsAsErrors != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rename WarningsAsErrors/Messages to something like GlobalWarningsAsErrors/Messages

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name is technically part of our public API already as a property to BuildParameters. I could rename the internal property on EventSourceSink if you feel strongly about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was more of a nit. Thought it's worth making it clear in the ILoggingService that WarningsAsErrors is the global, master switch and not the local per project one.

…ings.

Introduce MSBuildTreatWarningsAsErrors property that when set to true will treat all warnings as errors when building a project.
Introduce MSBuildWarningsAsErrors property which is a semicolon delmited list of warning codes to treat as errors when building a project.
Introduce MSBuildWarningsAsMessages property which is a semicolon delimited list of warning codes to treat as low importance messages.

This allows users to control warnings at the project level via standard MSBuild properties.  They can be set in a project, an import, or from the command-line.

The limitation here is that the warnings can only include ones that occur during a build.  This is because the properties are not read until after parsing so warnings generated during parse/evaluation happen too soon.  For these warnings, users will only be able to treat them as errors/messages with the /WarnAsError and /WarnAsMessage command-line arguments.

Closes dotnet#1886
Should reduce memory use when building large project trees
@jeffkl jeffkl merged commit 01f9915 into dotnet:master Apr 4, 2017
@jeffkl jeffkl deleted the warnaserrorprop branch April 4, 2017 22:37
cdmihai added a commit that referenced this pull request Apr 6, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants