Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Incremental and porting updates#110

Merged
marknfawaz merged 2 commits intomainfrom
mark-incrementalfix
Apr 26, 2021
Merged

Incremental and porting updates#110
marknfawaz merged 2 commits intomainfrom
mark-incrementalfix

Conversation

@marknfawaz
Copy link
Contributor

Related issue

Closes: #109

@marknfawaz marknfawaz added the enhancement New feature or request label Apr 23, 2021
Comment on lines +57 to +77
public List<GenericAction> AllActions
{
get
{
var allActions = new List<GenericAction>();
allActions.AddRange(AttributeActions);
allActions.AddRange(AttributeListActions);
allActions.AddRange(MethodDeclarationActions);
allActions.AddRange(ClassDeclarationActions);
allActions.AddRange(InterfaceDeclarationActions);
allActions.AddRange(ElementAccessActions);
allActions.AddRange(MemberAccessActions);
allActions.AddRange(IdentifierNameActions);
allActions.AddRange(InvocationExpressionActions);
allActions.AddRange(MemberAccessActions);
allActions.AddRange(UsingActions);
allActions.AddRange(ObjectCreationExpressionActions);
allActions.AddRange(NamespaceActions);
return allActions;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a specific reason or requirement for creating a new List when this property is called? If not, convert allActions to a private class variable and reassign a value to it in the getter to prevent a potential memory leak.

If this behavior is intentional, it may be more appropriate to convert this property to a method as properties are used to retrieve state rather than generate new objects.

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'm not sure I understand. How would this cause a memory leak?

Copy link
Contributor

@jonlouie jonlouie Apr 26, 2021

Choose a reason for hiding this comment

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

Memory leak might not be the best term here, but my thought is that it's possible to inadvertently consume more resources than expected. See the below example for what I was thinking, but if this is a nonconcern, we can forgo this modification.


Trivial example:

var allActions1 = nodeToken.AllActions;
var allActions2 = nodeToken.AllActions;

With the current implementation, this would allocate 2x the memory than the suggested implementation:

private List<GenericAction> _allActions;
public List<GenericAction> AllActions
{
    get
    {
        _allActions = new List<GenericAction>();
        _allActions.AddRange(AttributeActions);
        _allActions.AddRange(AttributeListActions);
        _allActions.AddRange(MethodDeclarationActions);
        _allActions.AddRange(ClassDeclarationActions);
        _allActions.AddRange(InterfaceDeclarationActions);
        _allActions.AddRange(ElementAccessActions);
        _allActions.AddRange(MemberAccessActions);
        _allActions.AddRange(IdentifierNameActions);
        _allActions.AddRange(InvocationExpressionActions);
        _allActions.AddRange(MemberAccessActions);
        _allActions.AddRange(UsingActions);
        _allActions.AddRange(ObjectCreationExpressionActions);
        _allActions.AddRange(NamespaceActions);
        return _allActions;
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed, this wouldn't allocate 2x memory because it's a local variable that gets disposed after the getter exits. We can look into this and the same behavior in fileactions to see if there's a better way to do it.

Comment on lines +59 to 64
private readonly string _portingInfoItemGroupTemplate =
@"<ItemGroup Label=""PortingInfo"">
<!-- DO NOT REMOVE WHILE PORTING
{0}
-->
</ItemGroup>";
Copy link
Contributor

Choose a reason for hiding this comment

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

To an end user, the messaging here is a little vague. What do you think about updating the ItemGroup Label to PortingAssistantMetadataReferences and/or updating the comment message to ADDED BY PORTING ASSISTANT. DO NOT REMOVE UNTIL PORTING IS COMPLETE. (or something similar that makes more sense)?

This would give the user context as to what these commented out references are, how they got there, and what their significance is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. Please create an issue for this, because it'll require a change here and on codelyzer. we will prioritize this based on availability.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, will create those issues

Comment on lines +84 to +88
//If true, line endings and spaces need to be normalized:
//if (result != root.ToFullString())
//{
// File.WriteAllText(sourceFileBuildResult.SourceFileFullPath, result);
//}
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete unused comments/code

Comment on lines 63 to +64

public SolutionRewriter(IDEProjectResult projectResult, List<ProjectConfiguration> solutionConfiguration)
Copy link
Contributor

Choose a reason for hiding this comment

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

Include doc comments

Comment on lines 97 to +98

public List<IDEFileActions> RunIncremental(RootNodes projectRules, List<string> updatedFiles)
Copy link
Contributor

Choose a reason for hiding this comment

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

Include doc comments


namespace CTA.Rules.Models
{
public class IDEFileActions
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a doc comment for the class that describes its use and how it differs from other file actions?

Also, would it make sense to rename anything with the prefix IDE to something more generic? Dependencies shouldn't be aware of the libraries or projects that consume them, but I also don't have full context here about how this model is consumed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't usually add doc comments for models. We can document our models classes at a later stage if needed.


var itemGroupContent = string.Format(_itemGroupTemplate, content);

var currentGroupTemplate = itemGroupTemplate ?? _itemGroupTemplate;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: rename _itemGroupTemplate to _defaultItemGroupTemplate

Comment on lines +56 to +103
if (_projectConfiguration.PortCode)
{
File.WriteAllText(sourceFileBuildResult.SourceFileFullPath, result);
}
var processedActions = ValidateActions(oneRewriter.allActions, result);
processedActions = AddActionsWithoutExecutions(currentFileActions, oneRewriter.allActions);

if (!actionsPerProject.TryAdd(sourceFileBuildResult.SourceFileFullPath, processedActions))
ActionsRewriter oneRewriter = new ActionsRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, currentFileActions.AllActions);
root = oneRewriter.Visit(root);
var result = root.NormalizeWhitespace().ToFullString();

if (!_projectConfiguration.IsMockRun)
{
File.WriteAllText(sourceFileBuildResult.SourceFileFullPath, result);
}

var processedActions = ValidateActions(oneRewriter.allExecutedActions, result);
processedActions = AddActionsWithoutExecutions(currentFileActions, oneRewriter.allExecutedActions);

if (!actionsPerProject.TryAdd(sourceFileBuildResult.SourceFileFullPath, processedActions))
{
throw new FilePortingException(sourceFileBuildResult.SourceFilePath, new Exception("File already exists in collection"));
}
}
else
{
throw new FilePortingException(sourceFileBuildResult.SourceFilePath, new Exception("File already exists in collection"));
if (currentFileActions != null)
{
currentFileActions.NodeTokens.ForEach(nodetoken =>
{
ActionsRewriter oneRewriter = new ActionsRewriter(sourceFileBuildResult.SemanticModel, sourceFileBuildResult.PrePortSemanticModel, sourceFileBuildResult.SyntaxGenerator, currentFileActions.FilePath, nodetoken.AllActions);

var result = root.NormalizeWhitespace().ToFullString();
//If true, line endings and spaces need to be normalized:
//if (result != root.ToFullString())
//{
// File.WriteAllText(sourceFileBuildResult.SourceFileFullPath, result);
//}

var newRoot = oneRewriter.Visit(root);
var allChanges = newRoot.SyntaxTree.GetChanges(root.SyntaxTree);

foreach (var textChange in allChanges)
{
var fileLinePositionSpan = root.SyntaxTree.GetMappedLineSpan(textChange.Span);
var newTextChange = new TextChange() { FileLinePositionSpan = fileLinePositionSpan, NewText = textChange.NewText };
if (!nodetoken.TextChanges.Contains(newTextChange))
{
nodetoken.TextChanges.Add(newTextChange);
}
}
});
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Each branch in this if...else block is quite large. What do you think about moving the logic for each branch into descriptive private functions to help with readability? For example:

if (_projectConfiguration.PortCode)
{
    ApplyCodeActionsAndPersist( ... );
}
else
{
    // assumes TextChanges are used to preview changes
    ApplyCodeActionsAndPreview( ... ); 
}

Comment on lines +118 to 174
if (_projectConfiguration.PortProject)
{
var projectActionExecution = new GenericActionExecution(projectLevelAction, _projectConfiguration.ProjectPath)
//Project Level Actions
foreach (var projectLevelAction in projectActions.ProjectLevelActions)
{
TimesRun = 1
};
var runResult = string.Empty;
if (!_projectConfiguration.IsMockRun)
{
if (projectLevelAction.ProjectLevelActionFunc != null)
var projectActionExecution = new GenericActionExecution(projectLevelAction, _projectConfiguration.ProjectPath)
{
TimesRun = 1
};
var runResult = string.Empty;
if (!_projectConfiguration.IsMockRun)
{
try
if (projectLevelAction.ProjectLevelActionFunc != null)
{
runResult = projectLevelAction.ProjectLevelActionFunc(_projectConfiguration.ProjectPath, projectType);
try
{
runResult = projectLevelAction.ProjectLevelActionFunc(_projectConfiguration.ProjectPath, projectType);
}
catch (Exception ex)
{
var actionExecutionException = new ActionExecutionException(projectLevelAction.Name, projectLevelAction.Key, ex);
projectActionExecution.InvalidExecutions = 1;
LogHelper.LogError(actionExecutionException);
}
}
catch (Exception ex)
else if (projectLevelAction.ProjectFileActionFunc != null)
{
var actionExecutionException = new ActionExecutionException(projectLevelAction.Name, projectLevelAction.Key, ex);
projectActionExecution.InvalidExecutions = 1;
LogHelper.LogError(actionExecutionException);
try
{
runResult = projectLevelAction.ProjectFileActionFunc(_projectConfiguration.ProjectPath,
projectType,
_projectConfiguration.TargetVersions,
projectActions.PackageActions.Distinct().ToDictionary(p => p.Name, p => p.Version),
projectActions.ProjectReferenceActions.ToList(),
_metadataReferences);
}
catch (Exception ex)
{
var actionExecutionException = new ActionExecutionException(projectLevelAction.Name, projectLevelAction.Key, ex);
projectActionExecution.InvalidExecutions = 1;
LogHelper.LogError(actionExecutionException);
}
}
}
else if (projectLevelAction.ProjectFileActionFunc != null)
if (!string.IsNullOrEmpty(runResult))
{
try
{
runResult = projectLevelAction.ProjectFileActionFunc(_projectConfiguration.ProjectPath, projectType, _projectConfiguration.TargetVersions, projectActions.PackageActions.Distinct().ToDictionary(p => p.Name, p => p.Version), projectActions.ProjectReferenceActions.ToList());
}
catch (Exception ex)
{
var actionExecutionException = new ActionExecutionException(projectLevelAction.Name, projectLevelAction.Key, ex);
projectActionExecution.InvalidExecutions = 1;
LogHelper.LogError(actionExecutionException);
}
projectActionExecution.Description = string.Concat(projectActionExecution.Description, ": ", runResult);
projectRunActions.Add(projectActionExecution);
LogHelper.LogInformation(projectLevelAction.Description);
}
}
if (!string.IsNullOrEmpty(runResult))

if (!actionsPerProject.TryAdd(Constants.Project, projectRunActions))
{
projectActionExecution.Description = string.Concat(projectActionExecution.Description, ": ", runResult);
projectRunActions.Add(projectActionExecution);
LogHelper.LogInformation(projectLevelAction.Description);
LogHelper.LogError(new FilePortingException(Constants.Project, new Exception("Error adding project to actions collection")));
}
}
Copy link
Contributor

@jonlouie jonlouie Apr 26, 2021

Choose a reason for hiding this comment

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

Same as above- consider moving the logic in this large if block to a private function called ApplyProjectLevelActions or something similar


namespace CTA.Rules.Models
{
public class TextChange
Copy link
Contributor

Choose a reason for hiding this comment

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

A doc comment for this class would be helpful as well

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable incremental and parallel assessments

3 participants