Roslyn Diagnostic Analyzer RegisterSymbolAction not being called - roslyn-code-analysis

I created a C# diagnostic project for VB, and am having trouble with it.
public override void Initialize(AnalysisContext context)
{
context.RegisterSymbolAction(CheckExpression,
SyntaxKind.InvocationExpression);
}
But the breakpoint on the first line of my CheckExpression method never gets hit.

There were two problems. The first problem was that nuget manager didn’t want to install the Visual Basic portion of the code analysis packages into the c# project, the second was at least partially caused by the first — the syntaxkind namespace is split between VisualBasic and CSharp, and all of course I was referencing the C# namespace. Once I managed to get the nuget packages installed (did this from the command line instead of the UI), I was able to reference the right namespaces for the vb syntax nodes and the anaylyzer portion is now working.
Hope this helps someone.

Related

Warning CS7022 - The entry point of the program is global code; ignoring 'Program.Main(string[])' entry point

so I have an issue where I have this warning in my Error List:
Severity Code Description Project File Line Suppression State
Warning CS7022 The entry point of the program is global code; ignoring 'Program.Main(string[])' entry point. Project DirectoryToProject 23 Active
This is essentially where its throwing
namespace MyProgram
{
class Program
{
static async Task Main(string[] args) => await new Program.MainAsync();
}
static async Task MainAsync()
{.. do stuff.. }
}
That is the line of code that is causing the error. I've tried playing around with the Main class, I did have it with the return type void and had my GetAwaiter and GetResult method called on the MainAsync method.
I've tried researching the error but I've had no luck, so hopefully, this thread will help a few others...
I am currently running on C# 9.0
Visual Studio 2019 Build Version: 16.8.30717.126
EDIT: Forgot to show that the MainAsync was in the file... (Sorry) Im trying to limit the amount of methods I show as 95% of them aren't useful the to question... But the issue is that although my application compiles, when executing my program it quits instantly as if it doesn't know where to start...
EDIT 2:
Thanks to Hans Passant -
If anyone experiences something like this try what he mentioned:
"This is a rather awful C# v9 feature. Project > Properties > Build tab, Advanced button > Language version = 7.3 You should now get a decent error message from the code you didn't know you had to post".
Essentially upon changing back to C# 8.0 I saw it was a different file hidden away causing the issue.
Starting with net5.0, I've found that this error can be caused by having stray semicolons above the namespace keyword. Whether this is a bug or intended behavior is beyond me, however make sure you don't have any standalone semicolons as such:
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
; // This will cause CS7022
namespace Tomoe.Commands.Public
Be sure to check all your files and not just Program.cs
EDIT: Apparently this is intended behavior, see https://github.com/dotnet/roslyn/issues/53472.
TL;DR, semicolons above namespaces are interpreted as top level statements. Because nothing is being called in said statement, the program exits. This is the same as doing
static void Main() {
;
}
in your Program.cs. While I do feel some change should be made, the design decision behind this is quite logical and entirely understandable.
EDIT 2: According to jcouv on Github, this is now becoming an error instead of a warning. Hopefully, this "bug" shall harass us no more!
This can happen if a file (any file) in the project has global code, that's to say statements outside of a class.
As mentioned by others, this is caused by a new C# 9 feature that is called "Top-level statements". This Feature enables you to write statements in the global context and the compiler will create it's own Main() based on that.
In my case I had a semicolon after my using statements in any of my files. As far as I know Visual Studio or the compiler don't give you any option to find this "entry-point" without changing any settings as descripted by others in this thread.
My solution was to just create another "Top-level statement entry point" in my project. Due to the fact that there is only one allowed the compiler complains about that.
I just added a semicolon directly after the using statements in my Program.cs. Because this file is one of the first that are processed by the compiler any other file that contains a "Top-level statement" will cause an error.
I've also seen this compiler error in the following scenario. You've written your code with top-level statements. Later, you decide to absorb that logic into a Main() method. (Maybe you find you now need to return an async Task, or you need to modify it to meet a company coding standard, for example.) Even though the following code block will compile (in VS2022 at least), it generates the error in question with a green squiggly beneath Main:
static void Main()
{
Console.WriteLine("Inside the Main() method");
//Do some other work here
}
Where's the issue? The method declaration is correct, and it will run, but even when this is the only code in the Program.cs file, and even when no other entry point is specified in the project/solution settings, we do not get the expected output:
Even the Microsoft documentation isn't much help in this case, because it pretty much repeats in more detail what the error is saying.
What's missing is the Program class definition. Without it, the compiler is still looking for a top-level statement - which it finds, namely static void. Then the next thing it finds is the Main() method declaration, but it finds this after the (unintended) top-level statement static void. Hence, the error sorta makes sense now.
The fix is to wrap the above code in a Program class:
class Program
{
static void Main()
{
Console.WriteLine("Inside the Main() method");
}
}
And now we get the expected output:

How to wrap all calls to an assembly with PostSharp?

My C# project refers to an external .NET assembly. I would like to insert locking statements around every call from my project to that assembly. I've been trying to establish this with PostSharp but can't find a way to do it. I have the source to the external assembly and I probably could achieve my goal the easiest by inserting the aspect there, but I prefer a non-intrusive solution where I can leave the external assembly untouched.
Approach 1
I have found out that I can wrap calls to the external assembly. Sadly, PostSharp is unable to wrap calls to abstract methods, and interface members are abstract methods. Therefore this approach doesn't cover calls through interface types.
[assembly: WrappingAspect(
AttributeTargetAssemblies = "Library",
AttributeTargetExternalMemberAttributes = MulticastAttributes.NonAbstract)]
[Serializable]
internal class WrappingAspect : OnMethodBoundaryAspect {
public override void OnEntry(MethodExecutionArgs args) {
Monitor.Enter(SyncRoot);
}
public override void OnExit(MethodExecutionArgs args) {
Monitor.Exit(SyncRoot);
}
}
Approach 2
Perhaps I could wrap all the methods in my project that refer to types in the external assembly. I'm thinking along the lines below. However, I cannot try this out because ReflectionSearch requires a PostSharp license that I don't currently have.
[assembly: WrappingAspect]
[Serializable]
internal class WrappingAspect : OnMethodBoundaryAspect {
public override void OnEntry(MethodExecutionArgs args) {
Monitor.Enter(SyncRoot);
}
public override void OnExit(MethodExecutionArgs args) {
Monitor.Exit(SyncRoot);
}
public override bool CompileTimeValidate(MethodBase method) {
return ReflectionSearch.GetDeclarationsUsedByMethod(method)
.Any(r => r.UsedType.Assembly.FullName.StartsWith("Library"));
}
}
Questions
Is there a non-intrusive way to wrap all calls to an external assembly, including calls to methods through an interface type?
Would my second approach work; to detect which methods refer to the external assembly and wrap them?
Are there other approaches to this problem?
Have you tried adding them via the XML approach? Straight from the PostSharp (slightly outdated) docs
Adding aspects through XML gives the advantage of applying aspects without modifying the source code, which could be an advantage in some legacy projects.
Answering my own question number 1; Yes, there is. Here's how I did it, using PostSharp configuration files as #Mikee suggested. I used PostSharp 3.1.39.
In short, you can run PostSharp to weave code into a DLL without changing the source code of that DLL. The command might look like this (split into multiple lines for readability)
postsharp.4.0-x64.exe temp\mylib.dll /P:Output=mylib.dll /NoLogo
/X:myconfig.psproj
"/P:ReferenceDirectory=$(ProjectDir) "
"/P:SearchPath=$(OutDir) "
"/P:Configuration=$(Configuration)"
"/P:Platform=$(Platform)"
"/P:MSBuildProjectFullPath=$(ProjectPath) "
/P:TargetFrameworkIdentifier=.NETFramework
The $(variables) in this command come straight out of Visual Studio, e.g. if you run this in your post-build event. Beware trailing backslashes in Visual Studio variables; adding an extra space before the closing quote is a necessary precaution.
mylib.dll is the target assembly where the weaving will be done. The input and output DLL must be two different files, hence the input is in a temp folder.
The configuration file myconfig.psproj looks like this in my case:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
<Multicast xmlns:my="clr-namespace:MyApp.Aspects;assembly:MyApp">
<my:MyAspect AttributeTargetMemberAttributes="Public"/>
</Multicast>
</Project>
This configuration will apply the aspect MyApp.Aspects.MyAspect from the MyApp assembly into all public members in the target assembly. More configuration attributes can be found from the documentation of MulticastAttribute
To run PostSharp in a more complex scenario, more configuration parameters may be required. Running postsharp.4.0-x64.exe /? gives you a somewhat unhelpful list of command line parameters. To find out what kind of parameters PostSharp really uses when it's run as part of a Visual Studio project, you can do this:
Add PostSharp to your C# project (as a NuGet).
Add some dummy aspect to a method.
Run the build with verbose output (in Visual Studio 2012: Tools -> Options -> Projects and Solutions -> Build and Run -> MSBuild project build output verbosity -> Diagnostic).
After the build, search the build output window for a line containing Task "PostSharp30" and then browse down to find a line starting with "Connected to the pipe after XXX ms. Requesting with XX arguments".
What follows on the line is a list of parameters to postsharp.4.0-x64.exe. Note that the parameters are separated by semicolons; remove the semicolons and quote the parameters to preserve meaningful spaces.
The list of parameters I got for my test project was much longer than the final command above. Many of the parameters weren't necessary.
Caveat: The free Express version of PostSharp doesn't support weaving iterator methods (ones that use return yield). You'll get warnings of them.

Strange behaviour when importing types in Scala 2.10

Today I cleared my .ivy cache and cleaned my project output targets. Since then I have been getting really strange behaviour when running tests with SBT or editing in the Scala IDE.
Given the following:
package com.abc.rest
import com.abc.utility.IdTLabel
I will get the following error:
object utility is not a member of package com.abc.rest.com.abc
Notice that com.abc is repeated twice, so it appears that the compiler uses the context of the current package when doing the import (maybe it's supposed to do this, but I never noticed it before).
Also, if I try to access classes in package com.abc from anywhere inside com.abc.rest (even using the full path) the compiler will complain that the type can not be found.
It appears that the errors only occur when I try to include files from parent packages. What I do find strange is that my code used to work. It only started happening after I cleaned up my project and my ivy cache, so maybe a later version of the compiler is more strict than the previous one.
I would love some ideas on what I can be doing wrong, or how I can go about troubleshooting this.
Update:
By first importing the parent classes and then defining the current package, the problem goes away:
import com.abc.utility.IdTLabel
import com.abs._
package com.abc.rest {
// Define classes belonging to com.abc.rest here
}
So this works, but I would still love to know why on earth the other way around worked, and then stopped working, and how on earth I can fix it. I had a good look, and could find no packages, objects or traits by the name of com anywhere inside the parent package.
Update relating to Worksheets:
Scala worksheets belonging to the same package share the same scope, which sounds obvious, but wasn't. Worksheets are not sand-boxed - they can see the project, and the project can see them. So all the 'test' object, traits, and classes you create inside the worksheet files, also becomes visible in the rest of the project.
I have so many worksheets that I did not even try to see where the problem came in. I simply moved them all to their own package, and like magic, the problem went away.
So, lesson learned for the day: If you create stuff inside worksheets, it's visible from outside the worksheet.
Anyway, this new found knowledge will come in handy, meaning anything 'interesting' can be build, monitored and tweaked inside the worksheet, while the rest of the project can actually use it. Quite cool actually.
It's still interesting to think how a sbt clean and cleaned up ivy cache managed to highlight the problem that was hidden before, but hey, that's another story....
(At the request of JacobusR, I'm making a proper answer out of my earlier comments).
This can happen if you have defined some class/trait/object inside package com.abc.rest.com. As soon as package com.abc.rest.com exists, and given that you are in package com.abc.rest, com would designate com.abc.rest.com as opposed to _root_.com. Fastest (but non-conclusive) way to check, without even scanning the source files, is to look for any .class files in the "com/abc/rest/com" sub-folder.
In particular you would get this behaviour if any of your files has duplicate package definitions (as in package com.abc.rest; package com.abc.rest; ...). If you have this duplicate package clause somewhere in the same file where you get the error, you wouldn't even see anything fishy with the .class files, as the failure at compiling the file would prevent the generation of .class files for any class definition inside the file.
The final bit of useful information is that as you found out the scala Worksheets are not sandboxed, and what you define in the worksheets affects your project's code (rather than only having the project's code affecting the worksheet). So a duplicate package clause in a worksheet could very well cause the error you got.
If package names conflict, there might be a custom error message for that. See if specifying the full path resolves the issue by starting from __root__. Ex. import __root__.com.foo.bar._

How to compare files programmatically in eclipse?

I am developing an eclipse plugin that runs code violation checker on the difference of two versions of a file. Right now I am using diff.exe to get the difference between the two files. But as diff.exe is an extrenal app, I realized that its better to use eclipse built-in compare tool to get the file difference.
So I used org.eclipse.compare and reached up to this point:
public static List<Patch> compare(String old, String recent) {
try{
IRangeComparator left = new TokenComparator(old); //what exactly to be passed in this constructor, a file path, a literal value or something else?
IRangeComparator right = new TokenComparator(recent);
RangeDifference[] diffs = RangeDifferencer.findDifferences(left, right); // This line is throwing NPE
//..
// Process RangeDifferences into Collection of Patch collection
//..
}catch(Exception e){}
//Returns a collection of file differences.
return null;
}
Now the problem is I am not sure what exactly to be passed in the constructor TokenComparator(String). The document says this constructor Creates a TokenComparator for the given string. But it is not written what exactly to be passed in this constructor, a file path, a literal value or something else? When I'm passing a file path or a string literal I am getting NullPointerException on the next line of finding differences.
java.lang.NullPointerException
at org.eclipse.compare.internal.core.LCS.isCappingDisabled(LCS.java:98)
at org.eclipse.compare.internal.core.LCS.longestCommonSubsequence(LCS.java:55)
at org.eclipse.compare.rangedifferencer.RangeComparatorLCS.longestCommonSubsequence(RangeComparatorLCS.java:186)
at org.eclipse.compare.rangedifferencer.RangeComparatorLCS.findDifferences(RangeComparatorLCS.java:31)
at org.eclipse.compare.rangedifferencer.RangeDifferencer.findDifferences(RangeDifferencer.java:98)
at org.eclipse.compare.rangedifferencer.RangeDifferencer.findDifferences(RangeDifferencer.java:82)
at org.eclipse.compare.rangedifferencer.RangeDifferencer.findDifferences(RangeDifferencer.java:67)
at com.dassault_systemes.eclipseplugin.codemonview.util.CodeMonDiff.compare(CodeMonDiff.java:48)
at com.dassault_systemes.eclipseplugin.codemonview.util.CodeMonDiff.main(CodeMonDiff.java:56)
Someone please tell what is right way to proceed.
If the question is What value the token comparators constructor takes then the answer is it takes the input string to compare. Specified in javadoc here http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fcompare%2Fcontentmergeviewer%2FTokenComparator.html
TokenComparator(String text)
Creates a TokenComparator for the given string.
And the null pointer yo are getting is because in function isCappingDisabled it tries to open the compare plugin which seems to be null. You seem to be missing a direct dependency to the plugin "org.eclipse.compare.core"
The org.eclipse.compare plugin was never meant to be used in standalone : many of its functionalities require a running instance of Eclipse. Furthermore, it mixes core and UI code within the same plugin, which will lead to unexpected behavior if you are not very careful about what you use and what dependencies are actually available in your environment.
You mentionned that you were developping an Eclipse plugin. However, the NPE you get indicates that you are not running your code as an Eclipse plugin, but rather as a standard Java program. In an Eclipse environment, ComparePlugin.getDefault() cannot return null : the plugin needs to be started for that call to return anything but null.... and the mere loading of the ComparePlugin class within Eclipse is enough to start it.
The answer will be a choice :
You need your code to run as a standalone Java program out of Eclipse. In such an event, you cannot use org.eclipse.compare and diff.exe is probably your best choice (or you could switch to an implementation of diff that was implemented in Java in order to be independent of the platform).
You do not need your program to work in a standalone environment, only as an Eclipse plugin. In this case, you can keep the code you're using. However, when you run your code, you have to launch it as a new "Eclipse application" instead of "Java Application". You might want to look at a tutorial on how to develop Eclipse plugins for this, This simple tutorial from Lars Vogel shows how to run a new Eclipse Application to test an Hello World plugin. You will need a similar code, with a menu entry to launch your plugin somewhere (right-click on a file then select "check violations" in your case?).

Netbeans - class does not have a main method

My program is just a simple System.out.println("");
But netbeans cannot find the main method.
Is netbeans 6.7.1 conflict with WIN7?
Any possible error?
This happens when you move your main class location manually because Netbeans doesn't refresh one of its property files.
Open nbproject/project.properties and change the value of main.class to the correct package location.
Sometimes passing parameters in the main method causes this problem eg. public static void main(String[] args,int a). If you declare the variable outside the main method, it might help :)
Exceute the program by pressing SHIFT+F6, instead of clicking the RUN button on the window.
This might be silly, bt the error main class not found is not occurring, the project is executing well...
It was most likely that you capitalized 'm' in 'main' to 'Main'
This happened to me this instant but I fixed it thanks to the various source code examples given by all those that responded. Thank you.
This destroyed me for a while.... I knew that there HAD to be an easier way with a world class IDE like Netbeans.
The easiest method is to press Shift+F11 (Clean and Build Project), then hit F6 to run it.
It refreshes Netbeans appropriately and finds your main without all the manual labor; and if you have multiple mains, it will give you the option to select the correct one.
Make sure it is
public static void main(String[] argv)
No other signature will do.
in Project window right click on your project and select properties go to Run and set Main Class ( you can brows it) . this manual work if you have static main in some class :
public class Someclass
{
/**
* #param args the command line arguments
*/
public static void main(String[] args)
{
//your code
}
}
Netbeans doesn't have any conflict with W7 and you can use version 6.8 .
If you named your class with the keyword in Java, your program wouldn't be recognized that it had the main method.
I had this issue as well (Error: Could not find or load main class test.Test). I'll explain this relatively basically since I know I would have appreciated someone doing that when I was looking for my answer.
When I right-clicked on the project (left hand side of the screen unless you got rid of the projects tab) and went to properties and then run, the main class had the projectname.classname, which is what confused me.
For example, I created a project "test" to test this out, and when I went to
(right-click) test or Source Packages -> properties -> run -> main class
had Test.test in that field, which is what the problem was. the class is test, not Test.test, so I clicked browse to its right, and the only thing in the list to select from was test, and when I selected that and tried rerunning it, it finally worked.
Additionally, I found that when you create a new project in Netbeans, one of the things it originally gives you (in my case of the project named test) is package test;. If you are having this problem, then like me, you probably originally got rid of that line seeing it as just another line of code you didn't need. That line of code is what enabled your main class which in my case was Test.test to find the main class *test from that.
My situation was different I believe because non of the above solutions di work for me. Let me share my situation.
I am importing an existing project (NewProject->Java->Import Existing Projects)
I name the project to xyz. The 'main' function exists in Main.class.
I try to run the code I modified in the main function but the error pops out. I tried the shift_f6, specifically rebuild. Nothing works.
Solution: I took the project properties and saw the 'Source Package Folder' mappings in the Sources branch was blank. I mapped it and voila it worked.
Now anyone might think that was very silly of me. Although I am new to Java and Netbeans this is not the first time I am importing sample projects and I saw all of them had the properties similar. The only difference I saw was that the main class was not having the name as the project which I believe is a java convention. I am using JDK7u51 (latest till date), is it causing the issue? I have no idea. But I am happy the project is running fine now.
Check for correct method declaration
public static void main(String [ ] args)
Check netbeans project properties in Run > main Class
While this may be an old question, the problem is still occurring these days, and the exact question is still not answered properly.
It is important to note that some projects have multiple classes with a main method.
In my case, I could run the project via the main class, but I could not run a particular other class that had a main method.
The only thing that helped me was refactoring the class and renaming it.
I've tried:
restart NetBeans
re-open the project
clear NetBeans cache
delete the file and create a new one with same name and contents
delete the file and create a new one with same name but very simple contents with only main method and print out message
rename the class (refactor) so a temp name and back
delete the project and create a new one with the same sources
The only thing that let me run this class is renaming it permanently. I think this must be some kind of a NetBeans bug.
Edit: Another thing that did help was completely uninstall Netbeans, wipe cache and any configuration files. It so happened that a newer Netbeans version was available so I installed it. But the old one would have probably worked too.
public class TestConnection {
public static void main(String args[]) {
//make sure when you create a new class, it has the above line, and then
//when you click shift+F6, it works fine for NetBeans IDE 12.4
myConnection my = new myConnection();
my.getConnection();
}
}